package ke24.ga.extension.adaptation.feedback;

import java.util.List;

import org.jgap.Configuration;
import org.jgap.IChromosome;
import org.jgap.IUniversalRateCalculator;
import org.jgap.InvalidConfigurationException;
import org.jgap.Population;
import org.jgap.RandomGenerator;
import ke24.ga.Package;
import ke24.ga.LoadDistributionFitnessFunction;
import ke24.ga.extension.*;

public class DeterministicLoadDistributionSwappingMutationOperator extends
        LoadDistributionSwappingMutationOperator{ 

    protected int t = 0;
    private double exponentFactor;
    
    
    /**
     * Constructs a new instance of this operator.
     * <p>
     * Attention: The configuration used is the one set with the static method
     * Genotype.setConfiguration.
     * 
     * @throws InvalidConfigurationException
     * 
     * @author Klaus Meffert
     */
    public DeterministicLoadDistributionSwappingMutationOperator()
            throws InvalidConfigurationException {
        super();
    }

    /**
     * @param a_config
     *            the configuration to use
     * @throws InvalidConfigurationException
     * 
     * @author Klaus Meffert
     * @since 3.0
     */
    public DeterministicLoadDistributionSwappingMutationOperator(
            final Configuration a_config) throws InvalidConfigurationException {
        super(a_config);
    }

    /**
     * Constructs a new instance of this operator with a specified mutation rate
     * calculator, which results in dynamic mutation being turned on.
     * 
     * @param a_config
     *            the configuration to use
     * @param a_mutationRateCalculator
     *            calculator for dynamic mutation rate computation
     * @throws InvalidConfigurationException
     * 
     * @author Klaus Meffert
     * @since 3.0 (previously: without a_config)
     */
    public DeterministicLoadDistributionSwappingMutationOperator(
            final Configuration a_config,
            final IUniversalRateCalculator a_mutationRateCalculator)
            throws InvalidConfigurationException {
        super(a_config, a_mutationRateCalculator);
        
        
    }

    /**
     * Constructs a new instance of this MutationOperator with the given
     * mutation rate.
     * 
     * @param a_config
     *            the configuration to use
     * @param a_desiredMutationRate
     *            desired rate of mutation, expressed as the denominator of the
     *            1 / X fraction. For example, 1000 would result in 1/1000 genes
     *            being mutated on average. A mutation rate of zero disables
     *            mutation entirely
     * @throws InvalidConfigurationException
     * 
     * @author tan
     */
    public DeterministicLoadDistributionSwappingMutationOperator(
            final Configuration a_config, final int a_desiredMutationRate)
            throws InvalidConfigurationException {
        super(a_config, a_desiredMutationRate);
        
    }
    
    void resetTime() {
        t = 0;
    }

    public void operate(final Population a_population,
            List a_candidateChromosomes) {
        t++;
        // this was a private variable, now it is local reference.
        final IUniversalRateCalculator m_mutationRateCalc = getMutationRateCalc();
        // If the mutation rate is set to zero and dynamic mutation rate is
        // disabled, then we don't perform any mutation.
        // ----------------------------------------------------------------
        if (getMutationRate() == 0 && m_mutationRateCalc == null) {
            return;
        }
        // Determine the mutation rate. If dynamic rate is enabled, then
        // calculate it based upon the number of genes in the chromosome.
        // Otherwise, go with the mutation rate set upon construction.
        // --------------------------------------------------------------
        int currentRate;
        if (m_mutationRateCalc != null) {
            currentRate = m_mutationRateCalc.calculateCurrentRate();
        } else {
            currentRate = getMutationRate();
        }
        
        System.out.println("Mutation rate at t = " + t + ": " + currentRate);

        RandomGenerator generator = getConfiguration().getRandomGenerator();
        // It would be inefficient to create copies of each Chromosome just
        // to decide whether to mutate them. Instead, we only make a copy
        // once we've positively decided to perform a mutation.
        // ----------------------------------------------------------------
        int size = a_population.size();
        for (int i = 0; i < size; i++) {
            IChromosome x = a_population.getChromosome(i);
            // This returns null if not mutated:
            IChromosome xm = operate(x, currentRate, generator);
            if (xm != null) {
                a_candidateChromosomes.add(xm);
            }
        }
    }
    
    

    public int getMutationRate() {                        
        double rate = super.getMutationRate() * Math.exp(((double)t)/getExponentFactor());        
        System.out.println("t = " + t + "initial rate = " + super.getMutationRate() + " exponent factor = "+ getExponentFactor() + " rate = " + rate);
        return (int)Math.round(rate);
    }

    public void setExponentFactor(double exponentFactor) {
        this.exponentFactor = exponentFactor;
    }

    public double getExponentFactor() {
        return exponentFactor;
    }
    
    protected void reset(int mutationRate) {
        setMutationRate(mutationRate);
        resetTime();
    }
    

}
